using Microsoft.EntityFrameworkCore.Storage;

namespace Crux.Core.EFCore;
/// <summary>
/// IUnitOfWorkOfT
/// </summary>
public interface IUnitOfWork<TContext>
    : IDisposableObservable, IAsyncDisposableObservable
    where TContext : DbContext
{
    /// <summary>
    ///
    /// </summary>
    TContext Context { get; }
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    TEntity Add<TEntity>(TEntity entity) where TEntity : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entity"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<TEntity> AddAsync<TEntity>(TEntity entity, CancellationToken cancellationToken = default) where TEntity : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    IEnumerable<TEntity> Add<TEntity>(IEnumerable<TEntity> entities) where TEntity : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="entities"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<IEnumerable<TEntity>> AddAsync<TEntity>(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default) where TEntity : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <returns></returns>
    T Update<T>(T entity) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <returns></returns>
    IEnumerable<T> UpdateRange<T>(IEnumerable<T> entities) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <param name="expression"></param>
    /// <returns></returns>
    int Update<T>(
        Expression<Func<T, bool>> where,
        Expression<Func<T, T>> expression) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<T> UpdateAsync<T>(
        T entity,
        CancellationToken cancellationToken = default) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<IEnumerable<T>> UpdateRangeAsync<T>(
        IEnumerable<T> entities,
        CancellationToken cancellationToken = default) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <param name="expression"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> UpdateAsync<T>(
        Expression<Func<T, bool>> where,
        Expression<Func<T, T>> expression,
        CancellationToken cancellationToken = default) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <returns></returns>
    T Delete<T>(T entity) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <returns></returns>
    IEnumerable<T> DeleteRange<T>(IEnumerable<T> entities) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <returns></returns>
    int Delete<T>(Expression<Func<T, bool>> where) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<T> DeleteAsync<T>(
        T entity,
        CancellationToken cancellationToken = default) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<IEnumerable<T>> DeleteRangeAsync<T>(
        IEnumerable<T> entities,
        CancellationToken cancellationToken = default) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> DeleteAsync<T>(
        Expression<Func<T, bool>> where,
        CancellationToken cancellationToken = default) where T : class;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <returns></returns>
    int SoftDelete<T>(Expression<Func<T, bool>> where) where T : class, ISoftDelete;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> SoftDeleteAsync<T>(Expression<Func<T, bool>> where, CancellationToken cancellationToken = default) where T : class, ISoftDelete;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <returns></returns>
    int PhysicsDelete<T>(Expression<Func<T, bool>> where) where T : class, ISoftDelete;
    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="where"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> PhysicsDeleteAsync<T>(Expression<Func<T, bool>> where, CancellationToken cancellationToken = default) where T : class, ISoftDelete;
    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    IDbContextTransaction BeginTranscation();
    /// <summary>
    ///
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<IDbContextTransaction> BeginTranscationAsync(CancellationToken cancellationToken = default);
    /// <summary>
    ///
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> ExecuteSqlInterpolatedAsync(FormattableString sql, CancellationToken cancellationToken = default);
    /// <summary>
    ///
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> ExecuteSqlAsync(FormattableString sql, CancellationToken cancellationToken = default);
    /// <summary>
    /// Executes the specified raw SQL command.
    /// </summary>
    /// <param name="sql">The raw SQL.</param>
    /// <param name="parameters">The parameters.</param>
    /// <returns>The number of state entities written to database.</returns>
    int ExecuteSqlRaw(string sql, IEnumerable<object> parameters);
    /// <summary>
    ///
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> ExecuteSqlRawAsync(string sql, CancellationToken cancellationToken = default);
    /// <summary>
    ///
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> ExecuteSqlRawAsync(string sql, IEnumerable<object> parameters, CancellationToken cancellationToken = default);
    /// <summary>
    ///
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    Task<int> ExecuteSqlRawAsync(string sql, params object[] parameters);
    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    int SaveChanges();
    /// <summary>
    ///
    /// </summary>
    /// <param name="acceptAllChangesOnSuccess"></param>
    /// <returns></returns>
    int SaveChanges(bool acceptAllChangesOnSuccess);
    /// <summary>
    ///
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
    /// <summary>
    ///
    /// </summary>
    /// <param name="acceptAllChangesOnSuccess"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default);
    /// <summary>
    ///
    /// </summary>
    void ClearChangeTracker();
    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    IUnitOfWork<TContext> SetTimeout(int? timeout);
}